home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Graphics Programming (2nd Edition) / Visual Basic Graphics Programming 2nd Edition.iso / OldSrc / CH12 / SRC / OBJPGON2.CLS < prev    next >
Encoding:
Text File  |  1996-04-05  |  21.5 KB  |  798 lines

  1. VERSION 1.0 CLASS
  2. BEGIN
  3.   MultiUse = -1  'True
  4. END
  5. Attribute VB_Name = "ObjPolygon"
  6. Attribute VB_Creatable = False
  7. Attribute VB_Exposed = False
  8. Option Explicit
  9.  
  10. ' Point3D is defined in module M3OPS.BAS as:
  11. '    Type Point3D
  12. '        coord(1 To 4) As Single
  13. '        trans(1 To 4) As Single
  14. '    End Type
  15.  
  16. Private NumPts As Integer ' Number of points.
  17. Private Points() As Point3D  ' Data points.
  18.  
  19. Private IsCulled As Boolean
  20.  
  21.  
  22. ' ************************************************
  23. ' Draw the transformed points on a Form, Printer,
  24. ' or PictureBox. Use the API function Polygon so
  25. ' the polygon will be properly filled to cover
  26. ' polygons behind it.
  27. '
  28. ' Assume the point light source is infinitely far
  29. ' away so the color is the same for the whole
  30. ' polygon.
  31. ' ************************************************
  32. Public Sub DrawShaded(canvas As Object, Optional r As Variant)
  33. Dim pts() As POINTAPI
  34. Dim pt As Integer
  35. Dim status As Integer
  36. Dim nx As Single
  37. Dim ny As Single
  38. Dim nz As Single
  39. Dim lx As Single
  40. Dim ly As Single
  41. Dim lz As Single
  42. Dim l_len As Single
  43. Dim intensity As Single
  44. Dim clr As Long
  45. Dim NdotL As Single
  46. Dim diffuse_part As Single
  47. Dim ambient_part As Single
  48.  
  49.     ' Don't draw if culled.
  50.     If IsCulled Then Exit Sub
  51.        
  52.     ' Fill in the point array.
  53.     ReDim pts(1 To NumPts)
  54.     For pt = 1 To NumPts
  55.         pts(pt).x = Points(pt).trans(1)
  56.         pts(pt).Y = Points(pt).trans(2)
  57.     Next pt
  58.  
  59.     ' Find the unit vector pointing towards the light.
  60.     lx = LightX - Points(1).coord(1)
  61.     ly = LightY - Points(1).coord(2)
  62.     lz = LightZ - Points(1).coord(3)
  63.     l_len = Sqr(lx * lx + ly * ly + lz * lz)
  64.     lx = lx / l_len
  65.     ly = ly / l_len
  66.     lz = lz / l_len
  67.     
  68.     ' Find the unit surface normal.
  69.     UnitNormalVector nx, ny, nz
  70.     
  71.     ' Calculate the part due to diffuse reflection.
  72.     NdotL = nx * lx + ny * ly + nz * lz
  73.     If NdotL < 0 Then
  74.         ' The light does not hit the surface.
  75.         diffuse_part = 0
  76.     Else
  77.         diffuse_part = LightKd * NdotL
  78.     End If
  79.     
  80.     ' Calculate the part due to ambient light.
  81.     ambient_part = LightIa * LightKa
  82.     
  83.     ' See how intense to make the color.
  84.     intensity = ambient_part + _
  85.         LightIi * diffuse_part
  86.  
  87.     ' Compute the color.
  88.     clr = &H2000000 + RGB(intensity, intensity, intensity)
  89.     canvas.FillColor = clr
  90.  
  91.     ' Draw the polygon.
  92.     On Error Resume Next
  93.     status = Polygon(canvas.hdc, pts(1), NumPts)
  94. End Sub
  95.  
  96.  
  97.  
  98. ' ************************************************
  99. ' Draw the transformed points on a Form, Printer,
  100. ' or PictureBox. Use the API function Polygon so
  101. ' the polygon will be properly filled to cover
  102. ' polygons behind it.
  103. ' ************************************************
  104. Public Sub DrawOrdered(canvas As Object, Optional r As Variant)
  105. Dim pts() As POINTAPI
  106. Dim pt As Integer
  107. Dim status As Integer
  108.  
  109.     ' Don't draw if culled.
  110.     If IsCulled Then Exit Sub
  111.        
  112.     ' Fill in the point array.
  113.     ReDim pts(1 To NumPts)
  114.     For pt = 1 To NumPts
  115.         pts(pt).x = Points(pt).trans(1)
  116.         pts(pt).Y = Points(pt).trans(2)
  117.     Next pt
  118.  
  119.     ' Draw the polygon.
  120.     On Error Resume Next
  121.     status = Polygon(canvas.hdc, pts(1), NumPts)
  122. End Sub
  123.  
  124.  
  125.  
  126. ' ************************************************
  127. ' Return the minimum and maximum coordinates.
  128. ' ************************************************
  129. Public Sub GetExtent(xmin As Single, xmax As Single, ymin As Single, ymax As Single, zmin As Single, zmax As Single)
  130. Dim i As Integer
  131. Dim x As Single
  132. Dim Y As Single
  133. Dim z As Single
  134.  
  135.     xmin = Points(1).trans(1)
  136.     xmax = xmin
  137.     ymin = Points(1).trans(2)
  138.     ymax = ymin
  139.     zmin = Points(1).trans(3)
  140.     zmax = zmin
  141.     For i = 2 To NumPts
  142.         x = Points(i).trans(1)
  143.         Y = Points(i).trans(2)
  144.         z = Points(i).trans(3)
  145.         If xmin > x Then xmin = x
  146.         If xmax < x Then xmax = x
  147.         If ymin > Y Then ymin = Y
  148.         If ymax < Y Then ymax = Y
  149.         If zmin > z Then zmin = z
  150.         If zmax < z Then zmax = z
  151.     Next i
  152. End Sub
  153.  
  154.  
  155.  
  156.  
  157. ' ************************************************
  158. ' Return the coordinates of a point on the polygon.
  159. ' ************************************************
  160. Public Sub GetTransformedPoint(index As Integer, x As Single, Y As Single, z As Single)
  161.     x = Points(index).trans(1)
  162.     Y = Points(index).trans(2)
  163.     z = Points(index).trans(3)
  164. End Sub
  165.  
  166.  
  167. ' ************************************************
  168. ' See where the projections of two segments cross.
  169. ' Return true if the segments cross, false
  170. ' otherwise.
  171. ' ************************************************
  172. Function FindCrossing( _
  173.     ax1 As Single, ay1 As Single, az1 As Single, _
  174.     ax2 As Single, ay2 As Single, az2 As Single, _
  175.     bx1 As Single, by1 As Single, bz1 As Single, _
  176.     bx2 As Single, by2 As Single, bz2 As Single, _
  177.     x As Single, Y As Single, z1 As Single, z2 As Single) _
  178.         As Boolean
  179. Dim dxa As Single
  180. Dim dya As Single
  181. Dim dza As Single
  182. Dim dxb As Single
  183. Dim dyb As Single
  184. Dim dzb As Single
  185. Dim t1 As Single
  186. Dim t2 As Single
  187. Dim denom As Single
  188.  
  189.     dxa = ax2 - ax1
  190.     dya = ay2 - ay1
  191.     dxb = bx2 - bx1
  192.     dyb = by2 - by1
  193.     
  194.     FindCrossing = False
  195.     
  196.     denom = dxb * dya - dyb * dxa
  197.     ' If the segments are parallel, stop.
  198.     If denom < 0.01 And denom > -0.01 Then Exit Function
  199.  
  200.     t2 = (ax1 * dya - ay1 * dxa - bx1 * dya + by1 * dxa) / denom
  201.     If t2 < 0 Or t2 > 1 Then Exit Function
  202.     
  203.     t1 = (ax1 * dyb - ay1 * dxb - bx1 * dyb + by1 * dxb) / denom
  204.     If t1 < 0 Or t1 > 1 Then Exit Function
  205.  
  206.     ' Compute the points of overlap.
  207.     x = ax1 + t1 * dxa
  208.     Y = ay1 + t1 * dya
  209.     dza = az2 - az1
  210.     dzb = bz2 - bz1
  211.     z1 = az1 + t1 * dza
  212.     z2 = bz1 + t2 * dzb
  213.     FindCrossing = True
  214. End Function
  215.  
  216. ' ************************************************
  217. ' Return the number of points.
  218. ' ************************************************
  219. Property Get NumPoints() As Integer
  220.     NumPoints = NumPts
  221. End Property
  222.  
  223. ' ************************************************
  224. ' Return true if this polygon partially obscures
  225. ' (has greater Z value than) polygon obj.
  226. '
  227. ' We assume one polygon may obscure the other, but
  228. ' they cannot obscure each other.
  229. '
  230. ' This check is executed by seeing where the
  231. ' projections of the edges of the polygons cross.
  232. ' Where they cross, see if one Z value is greater
  233. ' than the other.
  234. '
  235. ' If no edges cross, see if one polygon contains
  236. ' the other. If so, there is an overlap.
  237. ' ************************************************
  238. Public Function Obscures(obj As ObjPolygon) As Boolean
  239. Dim num As Integer
  240. Dim i As Integer
  241. Dim j As Integer
  242. Dim xi1 As Single
  243. Dim yi1 As Single
  244. Dim zi1 As Single
  245. Dim xi2 As Single
  246. Dim yi2 As Single
  247. Dim zi2 As Single
  248. Dim xj1 As Single
  249. Dim yj1 As Single
  250. Dim zj1 As Single
  251. Dim xj2 As Single
  252. Dim yj2 As Single
  253. Dim zj2 As Single
  254. Dim x As Single
  255. Dim Y As Single
  256. Dim z1 As Single
  257. Dim z2 As Single
  258.  
  259.     num = obj.NumPoints
  260.     
  261.     ' Check each edge in this polygon.
  262.     GetTransformedPoint NumPts, xi1, yi1, zi1
  263.     For i = 1 To NumPts
  264.         GetTransformedPoint i, xi2, yi2, zi2
  265.     
  266.         ' Compare with each edge in the other.
  267.         obj.GetTransformedPoint num, xj1, yj1, zj1
  268.         For j = 1 To num
  269.             obj.GetTransformedPoint j, xj2, yj2, zj2
  270.             ' See if the segments cross.
  271.             If FindCrossing( _
  272.                 xi1, yi1, zi1, _
  273.                 xi2, yi2, zi2, _
  274.                 xj1, yj1, zj1, _
  275.                 xj2, yj2, zj2, _
  276.                 x, Y, z1, z2) _
  277.             Then
  278.                 If z1 - z2 > 0.01 Then
  279.                     ' z1 > z2. We obscure it.
  280.                     Obscures = True
  281.                     Exit Function
  282.                 End If
  283.                 If z2 - z1 > 0.01 Then
  284.                     ' z2 > z1. It obscures us.
  285.                     Obscures = False
  286.                     Exit Function
  287.                 End If
  288.             End If
  289.             
  290.             xj1 = xj2
  291.             yj1 = yj2
  292.             zj1 = zj2
  293.         Next j
  294.         
  295.         xi1 = xi2
  296.         yi1 = yi2
  297.         zi1 = zi2
  298.     Next i
  299.     
  300.     ' No edges cross. See if one polygon contains
  301.     ' the other.
  302.     
  303.     ' If any points of one polygon are inside the
  304.     ' other, then they must all be. Since the
  305.     ' IsAbove tests were inconclusive, some points
  306.     ' in one polygon are on the "bad" side of the
  307.     ' other. In that case there is an overlap.
  308.     
  309.     ' See if this polygon is inside the other.
  310.     GetTransformedPoint 1, xi1, yi1, zi1
  311.     If obj.PointInside(xi1, yi1) Then
  312.         Obscures = True
  313.         Exit Function
  314.     End If
  315.     
  316.     ' See if the other polygon is inside this one.
  317.     obj.GetTransformedPoint 1, xi1, yi1, zi1
  318.     If PointInside(xi1, yi1) Then
  319.         Obscures = True
  320.         Exit Function
  321.     End If
  322.     
  323.     Obscures = False
  324. End Function
  325.  
  326. ' ************************************************
  327. ' Return true if the point projection lies within
  328. ' this polygon's projection.
  329. ' ************************************************
  330. Function PointInside(x As Single, Y As Single) As Boolean
  331. Dim i As Integer
  332. Dim theta1 As Double
  333. Dim theta2 As Double
  334. Dim dtheta As Double
  335. Dim dx As Double
  336. Dim dy As Double
  337. Dim angles As Double
  338.  
  339.     dx = Points(NumPts).trans(1) - x
  340.     dy = Points(NumPts).trans(2) - Y
  341.     theta1 = Arctan2(CSng(dx), CSng(dy))
  342.     If theta1 < 0 Then theta1 = theta1 + 2 * PI
  343.     For i = 1 To NumPts
  344.         dx = Points(i).trans(1) - x
  345.         dy = Points(i).trans(2) - Y
  346.         theta2 = Arctan2(CSng(dx), CSng(dy))
  347.         If theta2 < 0 Then theta2 = theta2 + 2 * PI
  348.         dtheta = theta2 - theta1
  349.         If dtheta > PI Then dtheta = dtheta - 2 * PI
  350.         If dtheta < -PI Then dtheta = dtheta + 2 * PI
  351.         angles = angles + dtheta
  352.         theta1 = theta2
  353.     Next i
  354.     
  355.     PointInside = (Abs(angles) > 0.001)
  356. End Function
  357.  
  358.  
  359. ' ************************************************
  360. ' Return true if this polygon is completly below
  361. ' the plane containing obj.
  362. ' ************************************************
  363. Public Function IsBelow(obj As ObjPolygon) As Boolean
  364. Dim nx As Single
  365. Dim ny As Single
  366. Dim nz As Single
  367. Dim px As Single
  368. Dim py As Single
  369. Dim pz As Single
  370. Dim dx As Single
  371. Dim dy As Single
  372. Dim dz As Single
  373. Dim cx As Single
  374. Dim cy As Single
  375. Dim cz As Single
  376. Dim i As Integer
  377.  
  378.     ' Compute a downward pointing normal to the plane.
  379.     obj.TransformedNormalVector nx, ny, nz
  380.     If nz > 0 Then
  381.         nx = -nx
  382.         ny = -ny
  383.         nz = -nz
  384.     End If
  385.     
  386.     ' Get a point on the plane.
  387.     obj.GetTransformedPoint 1, px, py, pz
  388.     
  389.     ' See if the points in this polygon all lie
  390.     For i = 1 To NumPts
  391.         ' Get the vector from plane to point.
  392.         dx = Points(i).trans(1) - px
  393.         dy = Points(i).trans(2) - py
  394.         dz = Points(i).trans(3) - pz
  395.             
  396.         ' If the dot product < 0, the point is
  397.         ' below the plane.
  398.         If dx * nx + dy * ny + dz * nz < -0.01 Then
  399.             IsBelow = False
  400.             Exit Function
  401.         End If
  402.     Next i
  403.     IsBelow = True
  404. End Function
  405.  
  406.  
  407. ' ************************************************
  408. ' Return true if this polygon is completly above
  409. ' the plane containing obj.
  410. ' ************************************************
  411. Public Function IsAbove(obj As ObjPolygon) As Boolean
  412. Dim nx As Single
  413. Dim ny As Single
  414. Dim nz As Single
  415. Dim px As Single
  416. Dim py As Single
  417. Dim pz As Single
  418. Dim dx As Single
  419. Dim dy As Single
  420. Dim dz As Single
  421. Dim cx As Single
  422. Dim cy As Single
  423. Dim cz As Single
  424. Dim i As Integer
  425.  
  426.     ' Compute an upward pointing normal to the plane.
  427.     obj.TransformedNormalVector nx, ny, nz
  428.     If nz < 0 Then
  429.         nx = -nx
  430.         ny = -ny
  431.         nz = -nz
  432.     End If
  433.     
  434.     ' Get a point on the plane.
  435.     obj.GetTransformedPoint 1, px, py, pz
  436.     
  437.     ' See if the points in this polygon all lie
  438.     For i = 1 To NumPts
  439.         ' Get the vector from plane to point.
  440.         dx = Points(i).trans(1) - px
  441.         dy = Points(i).trans(2) - py
  442.         dz = Points(i).trans(3) - pz
  443.             
  444.         ' If the dot product < 0, the point is
  445.         ' below the plane.
  446.         If dx * nx + dy * ny + dz * nz < -0.01 Then
  447.             IsAbove = False
  448.             Exit Function
  449.         End If
  450.     Next i
  451.     IsAbove = True
  452. End Function
  453.  
  454.  
  455. ' ***********************************************
  456. ' Return the maximum transformed Z value for this
  457. ' object.
  458. ' ***********************************************
  459. Property Get zmax() As Single
  460. Dim best As Single
  461. Dim z As Single
  462. Dim i As Integer
  463.  
  464.     best = Points(1).trans(3)
  465.     For i = 2 To NumPts
  466.         z = Points(i).trans(3)
  467.         If best < z Then best = z
  468.     Next i
  469.     zmax = best
  470. End Property
  471.  
  472.  
  473.  
  474.  
  475. ' ***********************************************
  476. ' Create a polyline representing the normal to
  477. ' this polygon and place it in the given objects
  478. ' collection.
  479. ' ***********************************************
  480. Sub CreateNormal(Objects As Collection)
  481. Dim pline As New ObjPolyline
  482. Dim x1 As Single
  483. Dim y1 As Single
  484. Dim z1 As Single
  485. Dim x2 As Single
  486. Dim y2 As Single
  487. Dim z2 As Single
  488.  
  489.     Objects.Add pline
  490.     UnitNormalSegment x1, y1, z1, x2, y2, z2
  491.     pline.AddSegment x1, y1, z1, x2, y2, z2
  492. End Sub
  493.  
  494. ' ***********************************************
  495. ' Compute a transformed normal vector.
  496. ' ***********************************************
  497. Public Sub TransformedNormalVector(nx As Single, ny As Single, nz As Single)
  498. Dim Ax As Single
  499. Dim Ay As Single
  500. Dim Az As Single
  501. Dim Bx As Single
  502. Dim By As Single
  503. Dim Bz As Single
  504.  
  505.     Ax = Points(2).trans(1) - Points(1).trans(1)
  506.     Ay = Points(2).trans(2) - Points(1).trans(2)
  507.     Az = Points(2).trans(3) - Points(1).trans(3)
  508.     Bx = Points(3).trans(1) - Points(2).trans(1)
  509.     By = Points(3).trans(2) - Points(2).trans(2)
  510.     Bz = Points(3).trans(3) - Points(2).trans(3)
  511.     m3Cross nx, ny, nz, Ax, Ay, Az, Bx, By, Bz
  512. End Sub
  513.  
  514.  
  515.  
  516. ' ***********************************************
  517. ' Compute a normal vector for this polygon.
  518. ' ***********************************************
  519. Public Sub NormalVector(nx As Single, ny As Single, nz As Single)
  520. Dim Ax As Single
  521. Dim Ay As Single
  522. Dim Az As Single
  523. Dim Bx As Single
  524. Dim By As Single
  525. Dim Bz As Single
  526.  
  527.     Ax = Points(2).coord(1) - Points(1).coord(1)
  528.     Ay = Points(2).coord(2) - Points(1).coord(2)
  529.     Az = Points(2).coord(3) - Points(1).coord(3)
  530.     Bx = Points(3).coord(1) - Points(2).coord(1)
  531.     By = Points(3).coord(2) - Points(2).coord(2)
  532.     Bz = Points(3).coord(3) - Points(2).coord(3)
  533.     m3Cross nx, ny, nz, Ax, Ay, Az, Bx, By, Bz
  534. End Sub
  535.  
  536.  
  537.  
  538.  
  539. ' ***********************************************
  540. ' Compute the unit normal line segment for this
  541. ' polygon.
  542. ' ***********************************************
  543. Sub UnitNormalSegment(x1 As Single, y1 As Single, z1 As Single, x2 As Single, y2 As Single, z2 As Single)
  544. Dim i As Integer
  545. Dim nx As Single
  546. Dim ny As Single
  547. Dim nz As Single
  548.     
  549.     UnitNormalVector nx, ny, nz
  550.     
  551.     x1 = 0
  552.     y1 = 0
  553.     z1 = 0
  554.     For i = 1 To NumPts
  555.         x1 = x1 + Points(i).coord(1)
  556.         y1 = y1 + Points(i).coord(2)
  557.         z1 = z1 + Points(i).coord(3)
  558.     Next i
  559.     x1 = x1 / NumPts
  560.     y1 = y1 / NumPts
  561.     z1 = z1 / NumPts
  562.  
  563.     x2 = x1 + nx
  564.     y2 = y1 + ny
  565.     z2 = z1 + nz
  566. End Sub
  567.  
  568.  
  569. ' ***********************************************
  570. ' Compute the unit normal vector for this
  571. ' polygon.
  572. ' ***********************************************
  573. Sub UnitNormalVector(nx As Single, ny As Single, nz As Single)
  574. Dim D As Single
  575.  
  576.     NormalVector nx, ny, nz
  577.     D = Sqr(nx * nx + ny * ny + nz * nz)
  578.     nx = nx / D
  579.     ny = ny / D
  580.     nz = nz / D
  581. End Sub
  582.  
  583.  
  584.  
  585.  
  586.  
  587. ' ***********************************************
  588. ' Set or clear the IsCulled flag.
  589. ' ***********************************************
  590. Property Let Culled(value As Boolean)
  591.     IsCulled = value
  592. End Property
  593.  
  594.  
  595. ' ***********************************************
  596. ' Return true if the polygon has been culled.
  597. ' ***********************************************
  598. Property Get Culled() As Boolean
  599.     Culled = IsCulled
  600. End Property
  601.  
  602. ' ***********************************************
  603. ' Return a string indicating the object type.
  604. ' ***********************************************
  605. Property Get ObjectType() As String
  606.     ObjectType = "POLYGON"
  607. End Property
  608.  
  609. ' ************************************************
  610. ' Add one or more points to the polygon.
  611. ' ************************************************
  612. Public Sub AddPoint(ParamArray coord() As Variant)
  613. Dim num_pts As Integer
  614. Dim i As Integer
  615. Dim pt As Integer
  616.  
  617.     num_pts = (UBound(coord) + 1) \ 3
  618.     ReDim Preserve Points(1 To NumPts + num_pts)
  619.  
  620.     pt = 0
  621.     For i = 1 To num_pts
  622.         Points(NumPts + i).coord(1) = coord(pt)
  623.         Points(NumPts + i).coord(2) = coord(pt + 1)
  624.         Points(NumPts + i).coord(3) = coord(pt + 2)
  625.         Points(NumPts + i).coord(4) = 1#
  626.         pt = pt + 3
  627.     Next i
  628.  
  629.     NumPts = NumPts + num_pts
  630. End Sub
  631.  
  632.  
  633. ' ************************************************
  634. ' Draw the object into a metafile.
  635. ' ************************************************
  636. Public Sub MakeWMF(mhdc As Integer)
  637. Dim pts() As POINTAPI
  638. Dim pt As Integer
  639. Dim status As Integer
  640.  
  641.     ' Don't draw if culled.
  642.     If IsCulled Then Exit Sub
  643.        
  644.     ' Fill in the point array.
  645.     ReDim pts(1 To NumPts)
  646.     For pt = 1 To NumPts
  647.         pts(pt).x = Points(pt).trans(1)
  648.         pts(pt).Y = Points(pt).trans(2)
  649.     Next pt
  650.  
  651.     ' Draw the polygon.
  652.     On Error Resume Next
  653.     status = Polygon(mhdc, pts(1), NumPts)
  654. End Sub
  655.  
  656. ' ***********************************************
  657. ' Fix the data coordinates at their transformed
  658. ' values.
  659. ' ***********************************************
  660. Public Sub FixPoints()
  661. Dim i As Integer
  662. Dim j As Integer
  663.  
  664.     For i = 1 To NumPts
  665.         For j = 1 To 3
  666.             Points(i).coord(j) = Points(i).trans(j)
  667.         Next j
  668.     Next i
  669. End Sub
  670.  
  671. ' ************************************************
  672. ' Apply a transformation matrix which may not
  673. ' contain 0, 0, 0, 1 in the last column to the
  674. ' object.
  675. ' ************************************************
  676. Public Sub ApplyFull(M() As Single)
  677. Dim i As Integer
  678.  
  679.     If IsCulled Then Exit Sub
  680.     For i = 1 To NumPts
  681.         m3ApplyFull Points(i).coord, M, Points(i).trans
  682.     Next i
  683. End Sub
  684.  
  685. ' ************************************************
  686. ' Apply a transformation matrix to the object.
  687. ' ************************************************
  688. Public Sub Apply(M() As Single)
  689. Dim i As Integer
  690.  
  691.     If IsCulled Then Exit Sub
  692.     For i = 1 To NumPts
  693.         m3Apply Points(i).coord, M, Points(i).trans
  694.     Next i
  695. End Sub
  696.  
  697.  
  698. ' ************************************************
  699. ' Apply a nonlinear transformation.
  700. ' ************************************************
  701. Public Sub Distort(D As Object)
  702. Dim i As Integer
  703.  
  704.     For i = 1 To NumPts
  705.         D.Distort Points(i).coord(1), Points(i).coord(2), Points(i).coord(3)
  706.     Next i
  707. End Sub
  708.  
  709. ' ************************************************
  710. ' Write a polyline to a file using Write.
  711. ' Begin with "POLYGON" to identify this object.
  712. ' ************************************************
  713. Public Sub FileWrite(filenum As Integer)
  714. Dim i As Integer
  715.  
  716.     Write #filenum, "POLYGON", NumPts
  717.     
  718.     ' Write the points.
  719.     For i = 1 To NumPts
  720.         Write #filenum, Points(i).coord(1), Points(i).coord(2), Points(i).coord(3)
  721.     Next i
  722. End Sub
  723.  
  724. ' ************************************************
  725. ' Draw the transformed points on a Form, Printer,
  726. ' or PictureBox.
  727. ' ************************************************
  728. Public Sub Draw(canvas As Object, Optional r As Variant)
  729. Dim pt As Integer
  730.  
  731.     ' Don't draw if culled.
  732.     If IsCulled Then Exit Sub
  733.     
  734.     On Error Resume Next
  735.     canvas.CurrentX = Points(NumPts).trans(1)
  736.     canvas.CurrentY = Points(NumPts).trans(2)
  737.     For pt = 1 To NumPts
  738.         canvas.Line _
  739.             -(Points(pt).trans(1), Points(pt).trans(2))
  740.     Next pt
  741. End Sub
  742. ' ***********************************************
  743. ' Cull if any points are behind the center of
  744. ' projection.
  745. ' ***********************************************
  746. Public Sub ClipEye(r As Single)
  747. Dim pt As Integer
  748.  
  749.     If IsCulled Then Exit Sub
  750.     For pt = 1 To NumPts
  751.         If Points(pt).trans(3) >= r Then Exit For
  752.     Next pt
  753.     If pt <= NumPts Then IsCulled = True
  754. End Sub
  755. ' ***********************************************
  756. ' Perform backface removal.
  757. ' ***********************************************
  758. Public Sub Cull(x As Single, Y As Single, z As Single)
  759. Dim Ax As Single
  760. Dim Ay As Single
  761. Dim Az As Single
  762. Dim nx As Single
  763. Dim ny As Single
  764. Dim nz As Single
  765.  
  766.     ' Compute a normal to the face.
  767.     NormalVector nx, ny, nz
  768.  
  769.     ' Compute a vector from the center of
  770.     ' projection to the face.
  771.     Ax = Points(1).coord(1) - x
  772.     Ay = Points(1).coord(2) - Y
  773.     Az = Points(1).coord(3) - z
  774.     
  775.     ' See if the vectors meet at an angle < 90.
  776.     IsCulled = (Ax * nx + Ay * ny + Az * nz > -0.0001)
  777. End Sub
  778.  
  779. ' ************************************************
  780. ' Read a polyline from a file using Input.
  781. ' Assume the "POLYGON" label has already been
  782. ' read.
  783. ' ************************************************
  784. Public Sub FileInput(filenum As Integer)
  785. Dim i As Integer
  786.  
  787.     Input #filenum, NumPts
  788.     
  789.     ' Allocate and read the points.
  790.     ReDim Points(1 To NumPts)
  791.     For i = 1 To NumPts
  792.         Input #filenum, Points(i).coord(1), Points(i).coord(2), Points(i).coord(3)
  793.         Points(i).coord(4) = 1#
  794.     Next i
  795. End Sub
  796.  
  797.  
  798.